//
// Created by kqbi on 2020/2/12.
//

#include "Util.h"
#include "boost/filesystem.hpp"
#include <initguid.h>
#ifdef _WIN32
#include <windows.h>
#endif

#if defined(__linux__)
#include <limits.h>
#include <unistd.h>
#endif

#include <ctime>

const char *getIPOSSStatusStr(enum VIICS_status s) {
    switch (s) {
#define XX(num, name, string) case VIICS_STATUS_##name: return #string;
        VIICS_STATUS_MAP(XX)
#undef XX
        default:
            return "<unknown>";
    }
}

std::string exePath() {
    char buffer[PATH_MAX * 2 + 1] = {0};
    int n = -1;
#if defined(_WIN32)
    n = GetModuleFileNameA(NULL, buffer, sizeof(buffer));
#elif defined(__MACH__) || defined(__APPLE__)
    n = sizeof(buffer);
    if (uv_exepath(buffer, &n) != 0) {
        n = -1;
    }
#elif defined(__linux__)
    n = readlink("/proc/self/exe", buffer, sizeof(buffer));
#endif

    std::string filePath;
    if (n <= 0) {
        filePath = "./";
    } else {
        filePath = buffer;
    }

#if defined(_WIN32)
    //windows下把路径统一转换层unix风格，因为后续都是按照unix风格处理的
    for (auto &ch : filePath) {
        if (ch == '\\') {
            ch = '/';
        }
    }
#endif //defined(_WIN32)

    return filePath;
}

std::string exeDir() {
    auto path = exePath();
    return path.substr(0, path.rfind('/') + 1);
}

std::string exeName() {
    auto path = exePath();
    return path.substr(path.rfind('/') + 1);
}

std::string getTimeStr(const char *fmt, time_t time) {
    std::tm tm_snapshot;
    if (!time) {
        time = ::time(NULL);
    }
#if defined(_WIN32)
    localtime_s(&tm_snapshot, &time); // thread-safe
#else
    localtime_r(&time, &tm_snapshot); // POSIX
#endif
    char buffer[1024];
    auto success = std::strftime(buffer, sizeof(buffer), fmt, &tm_snapshot);
    if (0 == success)
        return std::string(fmt);
    return buffer;
}

bool GetAllFiles(std::vector<std::string>& vecFiles, std::string iPath, bool bRecursive) {
    boost::filesystem::path mainPath(iPath);
    if (!exists(mainPath)) return FALSE;

    for (boost::filesystem::directory_entry &objInMainPath : boost::filesystem::directory_iterator(mainPath)) {
        if (boost::filesystem::is_regular_file(objInMainPath)) {
            vecFiles.push_back(objInMainPath.path().filename().string());
        } else if (boost::filesystem::is_directory(objInMainPath) && bRecursive) {
            GetAllFiles(vecFiles, objInMainPath.path().string(), bRecursive);
        }
    }

    return TRUE;
}

bool IsImageGDIPLUSValid(std::string filePath) {
    HANDLE hFile = CreateFile(filePath.c_str(), FILE_GENERIC_READ,      //  打开文件，获得文件读句柄
                              FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,     //  共享方式打开，避免其他地方需要读写此文件
                              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (INVALID_HANDLE_VALUE == hFile)                              //  文件打开失败，返回错误值
        return false;
    BYTE data[4] = { 0 };
    DWORD readSize;
    bool ok=false;
    if(ReadFile(hFile, data, 4, &readSize, NULL))
    {
        if (readSize == 4)
        {
            if (data[0] == 0xFF && data[1]==0xD8 && data[2]==0xFF)
            {
                ok = true;
            }
            else if (data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47)
            {
                ok = true;
            }
            else if (data[0] == 0x47 && data[1] == 0x49 && data[2] == 0x46 && data[3] == 0x38)
            {
                ok = true;
            }
            else if (data[0] == 0x49 && data[1] == 0x49 && data[2] == 0x2A && data[3] == 0x00)
            {
                ok = true;
            }
            else if (data[0] == 0x42 && data[1] == 0x4D)
            {
                ok = true;
            }
        }
    }
    CloseHandle(hFile);                                             //  关闭文件句柄，避免句柄泄露
    return ok;
}